package cn.poka.device;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import android_rfid_control.powercontrol;
import android_serialport_api.SerialPort;
import cn.poka.util.DeviceInfo;
import cn.poka.util.Tools;
import poka_global_constant.GlobalConstant;

/**
 * RFID设备类
 * @author digl
 */
public class RFIDDevice {

	/** RFID设备实例 */
	private static RFIDDevice rfidDevice;

	/** RFID序列化接口 */
	private static SerialPort rfidSerialPort;

	/** 通过RFID序列化接口，得到命令输入流 */
	private static InputStream mInput;

	/** 通过RFID序列化接口，得到命令输出流 */
	private static OutputStream mOutput;

	/** RFID设备 IO口一 */
	private static GPIO powerIO;

	/** RFID设备 IO口二 */
	private static GPIO enableIO;

	private byte[] selectEPC = null;

	public static final byte RESPONSE_OK = 0x00; //响应帧0K

//	private final byte R500_HEAD = (byte)0xA5;

	private final byte HEAD = (byte) 0xBB;
	private final byte END = (byte) 0x7E;

	private static powercontrol rFidPowerControl;

	private RFIDDevice(){

	}

	/**
	 * 获取RFID设备实例，如果实例为空，则进行初始化
	 * @return
	 */
	public static RFIDDevice getInstance(){
		if(rFidPowerControl == null){
			rFidPowerControl=new powercontrol();
			rFidPowerControl.openrfidPowerctl("/dev/rfidPowerctl");
			rFidPowerControl.rfidPowerctlSetSleep(0);
		}


		if(rfidDevice == null){
			if(rfidSerialPort == null){
				File rfidFile = new File(DeviceInfo.RFID_FILE);
				try {
					rfidSerialPort = new SerialPort(rfidFile,
							DeviceInfo.RFID_DEVICE_KEY, 0);

					powerIO = new GPIO(GlobalConstant.IO_RFID_POWER);
					enableIO = new GPIO(GlobalConstant.IO_RFID_ENABLE);

					mInput = rfidSerialPort.getInputStream();
					mOutput = rfidSerialPort.getOutputStream();

					rfidDevice = new RFIDDevice();
				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}

		return rfidDevice;
	}

//	/**
//	 * 给RFID设备上电
//	 */
//	public void enable(){
//		if(powerIO != null){
//			powerIO.setGPIO(GlobalConstant.ENABLE_IO);
//		}
//		if(enableIO != null){
//			enableIO.setGPIO(GlobalConstant.ENABLE_IO);
//		}
//	}
//
//	/**
//	 * 给RFID设备断电
//	 */
//	public void disenable(){
//		if(powerIO != null){
//			powerIO.setGPIO(GlobalConstant.DISABLE_IO);
//		}
//
//		if(enableIO != null){
//			enableIO.setGPIO(GlobalConstant.DISABLE_IO);
//		}
//	}

	/**
	 * 关闭RFID设备
	 */
	public void close(){
		if(rfidSerialPort != null){
			rfidSerialPort.close();
			rfidSerialPort = null;
			try {
				mInput.close();
				mOutput.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if(rfidDevice != null){
			rfidDevice = null;
		}

		if(rFidPowerControl != null){
			rFidPowerControl.rfidPowerctlSetSleep(1);
			rFidPowerControl.rfidPowerctlClose();
			rFidPowerControl = null;
		}
	}

	/**
	 * 发送指令
	 * @param cmd
	 */
	private void sendCMD(byte[] cmd){
		try {
			//通过RFID序列化输出流发送命令
			mOutput.write(cmd);
			mOutput.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 读取响应帧
	 * @return
	 */
	private byte[] read(){
		byte[] responseData = null;
		byte[] response = null;
		int available = 0 ;
		int index = 0;
		int headIndex = 0;
		//500ms内轮询无数据则，无数据返回
		try {
			while(index < 10){
				Thread.sleep(50);
				available = mInput.available();
				//缓冲区有数据
				if(available > 7) break;
				index++;
			}
			if(available > 0){
				responseData = new byte[available];
				mInput.read(responseData);
				for(int i = 0; i < available; i++){
					if(responseData[i] == 0xBB){
						headIndex = i;
						break;
					}
				}
				response = new byte[available - headIndex];
				System.arraycopy(responseData, headIndex, response, 0, response.length);

			}
		} catch (Exception e1) {
			e1.printStackTrace();
		}

		return response;
	}

//	/**
//	 * r500单次寻签
//	 * @return
//	 */
//	public String r500SingleRead(){
//		String result = "";
//		//A5 5A 00 0A 80 00 64 EE 0D 0A
//		byte[] cmd = {(byte)0xA5,(byte)0x5A,(byte)0x00,(byte)0x0A,(byte)0x80,(byte)0x00,(byte)0x64,(byte)0xEE,(byte)0x0D,(byte)0x0A};
//		sendCMD(cmd);
//		try {
//			Thread.sleep(50);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		byte[] response = this.read();
//		String responseStr = null;
//		if(response != null){
//			responseStr = Tools.Bytes2HexString(response, response.length);
//		}
//		System.out.println("单次寻签结果：" + responseStr);
//		int count = 0;
//		while(response == null || responseStr == null || responseStr.equals("") || responseStr.length() != 50){
//			count++;
//			System.out.println("第二次寻签:");
//			response = this.read();
//			if(response != null){
//				responseStr = Tools.Bytes2HexString(response, response.length);
//			}
//			if(count == 5){
//				responseStr = null;
//				break;
//			}
//			try {
//				Thread.sleep(50);
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
//		}
//		if(responseStr != null && !responseStr.equals("") && responseStr.length() == 50){
//			result = responseStr.substring(14,38);
//		}
//		return result;
//	}

//	/**
//	 * r500读标签EPC数据
//	 * @return
//	 */
//	public String r500ReadEPC(){
//		String result = "";
//		RFIDProtocol.init();
//    	RFIDProtocol.setType("84");
//    	RFIDProtocol.setMb("01");
//    	RFIDProtocol.setSa("0002");
//		RFIDProtocol.setDl("0006");
//		String protocol = RFIDProtocol.componentReadRfidMessage();
//		System.out.println("报文：" + protocol);
//		byte[] cmd = Tools.HexString2Bytes(protocol);
//		sendCMD(cmd);
//
//		byte[] response = this.read();
//		if(response != null){
//			String responseStr = Tools.Bytes2HexString(response, response.length);
//			System.out.println("读取数据的结果：" + responseStr);
//			result = RFIDProtocol.resolverRfidReadReplyMessage(responseStr);
//		}
//		return result;
//	}

//	/**
//	 * r500读标签UESR区数据
//	 * @return
//	 */
//	public String r500ReadUser(){
//		String result = "";
//		RFIDProtocol.init();
//    	RFIDProtocol.setType("84");
//    	RFIDProtocol.setMb("03");
//    	RFIDProtocol.setSa("0000");
//		RFIDProtocol.setDl("0013");
//		String protocol = RFIDProtocol.componentReadRfidMessage();
//		System.out.println("报文：" + protocol);
//		byte[] cmd = Tools.HexString2Bytes(protocol);
//		sendCMD(cmd);
//
//		byte[] response = this.read();
//		if(response != null){
//			String responseStr = Tools.Bytes2HexString(response, response.length);
//			System.out.println("读取数据的结果：" + responseStr);
//			result = RFIDProtocol.resolverRfidReadReplyMessage(responseStr);
//		}
//
//
//
//		return result;
//	}

//	/**
//	 * r500写USER区数据
//	 * @param data
//	 * @return
//	 */
//	public boolean r500WrieUser(String operateCode){
//		System.out.println("user data:" + operateCode);
//		boolean flag = false;
//		RFIDProtocol.init();
//    	RFIDProtocol.setType("86");
//    	RFIDProtocol.setMb("03");
//    	RFIDProtocol.setSa("0000");
//		RFIDProtocol.setDl("0013");
//		String data = "000000000000000000"+operateCode+"00000000000000000000000000000000000000000000000000000000";
//		RFIDProtocol.setUserData(data);
//		String protocol = RFIDProtocol.componentWriteRfidMessage();
//		System.out.println("=====报文：" + protocol);
//		byte[] cmd = Tools.HexString2Bytes(protocol);
//		sendCMD(cmd);
//
//		byte[] response = this.read();
//		if(response != null){
//			String responseStr = Tools.Bytes2HexString(response, response.length);
//			System.out.println("responseStr:" + responseStr);
//			flag = RFIDProtocol.resolverRfidWriteReplyMessage(responseStr);
//		}
//		return flag;
//	}

//	/**
//	 * r500写EPC区数据
//	 * @param data
//	 * @return
//	 */
//	public boolean r500WriteEPC(String data){
//		System.out.println("user data:" + data);
//		boolean flag = false;
//		RFIDProtocol.init();
//    	RFIDProtocol.setType("86");
//    	RFIDProtocol.setMb("01");
//    	RFIDProtocol.setSa("0002");
//		RFIDProtocol.setDl("0006");
//		RFIDProtocol.setEpcData(data);
//		String protocol = RFIDProtocol.componentWriteRfidMessage();
////		String result = rfidDevice.readSingle(message,10);
//		System.out.println("=====报文：" + protocol);
////		boolean flag = RFIDProtocol.resolverRfidWriteReplyMessage(result);
//		byte[] cmd = Tools.HexString2Bytes(protocol);
//		sendCMD(cmd);
//
//		byte[] response = this.read();
//		if(response != null){
//			String responseStr = Tools.Bytes2HexString(response, response.length);
//			System.out.println("responseStr:" + responseStr);
//			flag = RFIDProtocol.resolverRfidWriteReplyMessage(responseStr);
//		}
//		return flag;
//	}

	public String newRead(){
		List<byte[]> list = inventoryRealTime();
		if(list != null && list.size() > 0){
			byte[] buf = list.get(0);
			String result = Tools.Bytes2HexString(buf, buf.length);
			return result;
		}else{
			return "";
		}
	}

	/**
	 * 实时盘存
	 */
	public List<byte[]> inventoryRealTime() {
		List<byte[]> list = new ArrayList<byte[]>();
		try {
			Log.d("tag__", "--实时盘存--1");
			byte[] cmd = {(byte)0xBB ,(byte)0x00 ,(byte)0x22 ,(byte)0x00 ,
					(byte)0x00 ,(byte)0x22 ,(byte)0x7E};
			sendCMD(cmd);

			byte[] response = this.read();
			if(response != null){
				Log.d("tag__", "--实时盘存--1");
				int responseLength = response.length;
				Log.d("tag__", "--实时盘存--1" + responseLength);

//				Log.e("", Tools.Bytes2HexString(response, response.length));
				int start = 0;
				//单张卡返回的数据
//				byte[] sigleCard = new byte[24];
				//多张卡片，将以多条帧 的格式返回
				if(responseLength > 15){
//					Log.e("多张卡", Tools.Bytes2HexString(response, response.length));
					//要取到数据长度
					while(responseLength > 5){
//						Log.e("多张卡", Tools.Bytes2HexString(response, response.length));
						//获取完整的一条指令
						int paraLen = response[start + 4]&0xff;
						int singleCardLen = paraLen + 7;
						//指令不完整跳出
						if(singleCardLen > responseLength) break;
						byte[] sigleCard = new byte[singleCardLen];
						System.arraycopy(response, start, sigleCard, 0, singleCardLen);

						byte[] resolve = handlerResponse(sigleCard);
//						Log.e("多张卡", Tools.Bytes2HexString(resolve, resolve.length));
						//处理后的数据第一位是指令代码，第2位RSSI，第3-4位是PC，第5位到最后是EPC
						if(resolve != null && paraLen > 5){
							byte[] epcBytes = new byte[paraLen - 5];
							System.arraycopy(resolve, 4, epcBytes, 0, paraLen - 5);
//							Log.e("处理EPC", Tools.Bytes2HexString(epcBytes, epcBytes.length));
							list.add(epcBytes);
						}
						start+=singleCardLen;
						responseLength-=singleCardLen;
					}
				}else{
					handlerResponse(response);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	public String readSingStr(){
		//读标签数据存储区 BB 00 39 00 09 00 00 FF FF 03 00 00 00 02 45 7E
		byte[] cmd = {(byte)0xBB, (byte)0x00, (byte)0x39, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF,
				(byte)0x03, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x45, (byte)0x7E};
		sendCMD(cmd);


		return null;
	}

	/***
	 * 获取RFID发射功率
	 */
	public short getPower(){
		byte[] cmd = {(byte)0xBB,(byte)0x00,(byte)0xB7,(byte)0x00,(byte)0x00,(byte)0xB7,(byte)0x7E};
		sendCMD(cmd);
		byte[] recv = read();
		if(recv != null){
			Log.e("tag_", "getPower:" + Tools.Bytes2HexString(recv, recv.length));
		}
		byte[] data = handlerResponsegetPower(recv);
		if(data == null){
			return 0;
		}
		short power = Tools.byteToShort(data);
		Log.d("tag__", "getPower() power:" + power);
		return power;
	}

	/***
	 * 设置RFID发射功率
	 */
	public boolean setPower(short powerVal){
		byte[] cmd = {(byte)0xBB,(byte)0x00,(byte)0xB6,(byte)0x00,(byte)0x02,(byte)0x07,(byte)0xD0,(byte)0x8F,(byte)0x7E};
		byte[] buffer = Tools.shortToByte(powerVal);
		cmd[5] = buffer[0];
		cmd[6] = buffer[1];
		cmd[7] = checkSum(cmd);
		sendCMD(cmd);

		byte[] recv = read();
		if(recv != null){
			Log.e("tag_", "setPower:" + Tools.Bytes2HexString(recv, recv.length));
		}
		byte[] data = handlerResponseSetPower(recv);
		if(data == null){
			return false;
		}
		if(data[0] == 0x00){
			return true;
		}
		return false;
	}

	private byte[] handlerResponsegetPower(byte[] response) {
		byte[] data = null;
		int responseLength = response.length;
		if(response[0] != HEAD) {
			Log.e("tag__", "head error");
			return data;
		}
		if(response[responseLength - 1] != END){
			Log.e("tag__", "end error");
			return data;
		}
		if(response[1] != 0x01) {
			Log.e("tag__", "type error");
			return data;
		}
		Log.e("tag__", "response[2]" + response[2]);
		if(response[2] != (byte)0xB7) {
			Log.e("tag__", "command error");
			return data;
		}
		data = new byte[2];
		data[0] = response[5];
		data[1] = response[6];
		return data;
	}

	private byte[] handlerResponseSetPower(byte[] response) {
		byte[] data = null;
		int responseLength = response.length;
		if(response[0] != HEAD) {
			Log.e("tag__", "head error");
			return data;
		}
		if(response[responseLength - 1] != END){
			Log.e("tag__", "end error");
			return data;
		}
		if(response[1] != 0x01) {
			Log.e("tag__", "type error");
			return data;
		}
		Log.e("tag__", "response[2]" + response[2]);
		if(response[2] != (byte)0xB6) {
			Log.e("tag__", "command error");
			return data;
		}
		data = new byte[1];
		data[0] = response[5];
		return data;
	}

	public int setWorkArea(int area){
		//BB 00 07 00 01 01 09 7E
		byte[] cmd = {(byte)0xBB ,(byte)0x00 ,(byte)0x07 ,(byte)0x00 ,(byte)0x01 ,(byte)0x01 ,(byte)0x09 ,(byte)0x7E };
		cmd[5] = (byte) area;
		cmd[6] = checkSum(cmd);
		sendCMD(cmd);
		byte[] recv = read();
		if(recv != null){
			Log.e("setWorkArea",Tools.Bytes2HexString(recv, recv.length));
			handlerResponse(recv);
		}
		return 0;
	}

	public String writeSingStr(Context context){
		Log.d("tag__","写标签数据存储区  begin");
		//写标签数据存储区
		byte[] cmd = {(byte)0xBB,(byte)0x00,(byte)0x49,(byte)0x00,(byte)0x0D,(byte)0x00,(byte)0x00,(byte)0xFF,
				(byte)0xFF,(byte)0x03,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0x12,(byte)0x34,
				(byte)0x56,(byte)0x78,(byte)0x6D,(byte)0x7E};
		cmd[7] = (byte)0x00;
		cmd[8] = (byte)0x00;
		cmd[9] = (byte)0x01;
		cmd[18] = checkSum(cmd);
		sendCMD(cmd);
		byte[] recv = read();
		if(recv != null){
			String result = Tools.Bytes2HexString(recv, recv.length);
			Log.d("tag__","写数据响应 result=" + result);
			Toast.makeText(context, "写数据响应 result=" + result, Toast.LENGTH_SHORT).show();
			//handlerResponse(recv);
		}
		return "";
	}

	/**
	 * 处理响应帧
	 * @param response
	 * @return
	 */
	private byte[] handlerResponse(byte[] response){
		byte[] data = null;
		byte crc = 0x00;
		int responseLength = response.length;
		if(response[0] != HEAD) {
			Log.e("handlerResponse", "head error");
			return data;
		}
		if(response[responseLength - 1] != END){
			Log.e("handlerResponse", "end error");
			return data;
		}
		if(responseLength < 7) return data;
		//转成无符号int
		int lengthHigh = response[3]&0xff;
		int lengthLow = response[4]&0xff;
		int dataLength = lengthHigh*256 + lengthLow;
		//计算CRC
		crc = checkSum(response);
		if(crc != response[responseLength - 2]){
			Log.e("handlerResponse", "crc error");
			return data;
		}
		if(dataLength != 0 && responseLength == dataLength + 7){
			Log.e("handlerResponse", "response right");
			data = new byte[dataLength + 1];
			data[0] = response[2];
			System.arraycopy(response, 5, data, 1, dataLength);
		}
		return data;
	}

	public byte checkSum(byte[] data) {
		byte crc = 0x00;
		//从指令类型累加到参数最后一位
		for(int i = 1; i < data.length - 2; i++){
			crc+=data[i];
		}
		return crc;
	}

	/**
	 * 写数据
	 * byte[] password 访问密码
	 * int memBank 数据区(注意：如果是EPC区 起始地址从2开始)
	 * int startAddr 起始地址（以WORD为单位）
	 * int wordCnt 写入数据的长度（以WORD为单位 1word = 2bytes）
	 * byte[] data 写入数据
	 * 返回 boolean，true写入数据正确，false写入数据失败
	 */
	public boolean writeTo6C(byte[] password, int memBank, int startAddr,
							 int dataLen, byte[] data) {


		//进行读写操作前线选择操作的卡
		this.setSelectPara();
		if(password == null || password.length != 4){
			return false;
		}
		boolean writeFlag = false;
		int cmdLen = 16 + data.length;
		int parameterLen = 9 + data.length;
		byte[] cmd = new byte[cmdLen];
		cmd[0] = (byte) 0xBB;
		cmd[1] = 0x00;
		cmd[2] = 0x49;
		if(parameterLen < 256){
			cmd[3] = 0x00;
			cmd[4] = (byte)parameterLen;
		}else{
			int paraH = parameterLen/256;
			int paraL = parameterLen%256;
			cmd[3] = (byte)paraH;
			cmd[4] = (byte)paraL;
		}
		System.arraycopy(password, 0, cmd, 5, 4);
		cmd[9] = (byte)memBank;
		if(startAddr < 256){
			cmd[10] = 0x00;
			cmd[11] = (byte) startAddr;
		}else{
			int startH = startAddr/256;
			int startL = startAddr%256;
			cmd[10] = (byte) startH;
			cmd[11] = (byte) startL;
		}
		if(dataLen < 256){
			cmd[12] = 0x00;
			cmd[13] = (byte) dataLen;
		}else{
			int dataLenH = dataLen/256;
			int dataLenL = dataLen%256;
			cmd[12] = (byte)dataLenH;
			cmd[13] = (byte)dataLenL;
		}
		System.arraycopy(data, 0, cmd, 14, data.length);
		cmd[cmdLen -2] = checkSum(cmd);
		cmd[cmdLen - 1] = (byte)0x7E;
//		Log.e("write data", Tools.Bytes2HexString(cmd, cmdLen));
		sendCMD(cmd);
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		byte[] response = this.read();
		if(response != null) {
//			Log.e("write data response", Tools.Bytes2HexString(response, response.length));
			byte[] resolve = this.handlerResponse(response);
			if(resolve != null){
//				Log.e("write data resolve", Tools.Bytes2HexString(resolve, resolve.length));
				if(resolve[0] == 0x49 && resolve[resolve.length - 1] == RESPONSE_OK){
					writeFlag = true;
				}
			}
		}

		return writeFlag;
	}

	private void setSelectPara(){
		byte[] cmd = {(byte)0xBB ,(byte)0x00,(byte)0x0C ,(byte)0x00 ,(byte)0x13 ,
				(byte)0x01 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,(byte)0x20 ,(byte)0x60 ,
				(byte)0x00 ,(byte)0x01 ,(byte)0x61 ,(byte)0x05 ,(byte)0xB8 ,(byte)0x03 ,
				(byte)0x48 ,(byte)0x0C ,(byte)0xD0 ,(byte)0x00 ,(byte)0x03 ,(byte)0xD1 ,
				(byte)0x9E ,(byte)0x58 ,(byte)0x7E};
		if(this.selectEPC != null ){
			Log.e("", "select epc");
			System.arraycopy(selectEPC, 0, cmd, 12, selectEPC.length);
			cmd[cmd.length - 2] = checkSum(cmd);
//			Log.e("setSelectPara", Tools.Bytes2HexString(cmd, cmd.length));
			sendCMD(cmd);
			byte[] response = this.read();
			if(response != null){}
//			Log.e("setSelectPara response", Tools.Bytes2HexString(response, response.length));
		}
	}

	public void selectEPC(byte[] epc) {
		byte[] cmd = {(byte)0xBB ,(byte)0x00 ,(byte)0x12 ,(byte)0x00,
				(byte)0x01 ,(byte)0x00 ,(byte)0x13 ,(byte)0x7E };
		this.selectEPC = epc;
		sendCMD(cmd);
		byte[] response = this.read();
		if(response != null){
//			Log.e("select epc", Tools.Bytes2HexString(response, response.length));
		}

	}

}

































